/**
 * @file port_ble_msg.h
 * @brief 
 * @author dotc (dotchan@qq.com)
 * @date 2025-01-21
 * 
 * @copyright Copyright (c) 2025 by 深圳市鹏天微智能科技有限公司, All Rights Reserved.
 */

#ifndef __PORT_BASE_H__
#define __PORT_BASE_H__

#if defined(CONFIG_PORT_BLE_ENABLE)

/* ==================== [Includes] ========================================== */

#include "xf_utils.h"
#include "gatt.h"
#include "gapm.h"
#include "gapc.h"

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== [Defines] =========================================== */
#define _TID_BASE           (TID_LLC)
#define _TID_MAX            (TID_MESH +1)
#define _GAPC_MSG_ID_MAX    (GAPC_SET_PREF_SLAVE_LATENCY_CMD + 1)
#define _GAPM_MSG_ID_MAX    (GAPM_DEV_RF_PATH_COMP_IND + 1)
#define _GATT_MSG_ID_MAX    (GATT_CON_INFO_IND + 1)

/* ==================== [Typedefs] ========================================== */

typedef enum type_id type_id_t;
typedef msg_func_t port_msg_grp_handler_t;
typedef type_id_t port_msg_grp_id_t;
/**
 * @brief 消息组类型 (值)
 * @note 与 SDK 侧 enum type_id 相关，但稍有不同
 */
typedef uint8_t port_msg_grp_type_t;
enum _port_msg_grp_type_t{
    _PORT_MSG_GRP_TYPE_BASE = 0,
    PORT_MSG_GRP_TYPE_LLC = _PORT_MSG_GRP_TYPE_BASE,
    PORT_MSG_GRP_TYPE_LLD,
    PORT_MSG_GRP_TYPE_HCI,
    PORT_MSG_GRP_TYPE_L2CC,
    PORT_MSG_GRP_TYPE_GATT,
    PORT_MSG_GRP_TYPE_GAPM,
    PORT_MSG_GRP_TYPE_GAPC,
    _PORT_MSG_GRP_TYPE_UNKNOWN_8,   // SDK 侧一个无标明意义的空缺值
    PORT_MSG_GRP_TYPE_APP,
    PORT_MSG_GRP_TYPE_MESH,
    _PORT_MSG_GRP_TYPE_MAX,
};

#define PORT_MSG_GRP_GET_FROM_TID(tid)  (tid - (_TID_BASE-_PORT_MSG_GRP_TYPE_BASE))

#define PORT_MSG_TBL_ITEM_SIZE    (sizeof(uint8_t))
#define PORT_MSG_TBL_ITEM_BIT_CNT (PORT_MSG_TBL_ITEM_SIZE*8)

/**
 * @brief 各消息索引 (msg_index) 的最大值
 * @attention SDK 侧直接引用的值
 */
#define MSG_INDEX_MAX_LLC       1
#define MSG_INDEX_MAX_LLD       1
#define MSG_INDEX_MAX_HCI       1
#define MSG_INDEX_MAX_L2CC      1
#define MSG_INDEX_MAX_GATT      MSG_IDX(_GATT_MSG_ID_MAX)
#define MSG_INDEX_MAX_GAPM      MSG_IDX(_GAPM_MSG_ID_MAX)
#define MSG_INDEX_MAX_GAPC      MSG_IDX(_GAPC_MSG_ID_MAX)
#define MSG_INDEX_MAX_APP       1
#define MSG_INDEX_MAX_MESH      1

/**
 * @brief 各消息组 (msg_grp) 在消息表 (msg_tbl) 中需要的条目 (item) (成员) 数
 */
#define PORT_MSG_GRP_TBL_ITEM_CNT_LLC       1
#define PORT_MSG_GRP_TBL_ITEM_CNT_LLD       1
#define PORT_MSG_GRP_TBL_ITEM_CNT_HCI       1
#define PORT_MSG_GRP_TBL_ITEM_CNT_L2CC      1
#define PORT_MSG_GRP_TBL_ITEM_CNT_GATT      (MSG_INDEX_MAX_GATT/PORT_MSG_TBL_ITEM_BIT_CNT+1)
#define PORT_MSG_GRP_TBL_ITEM_CNT_GAPM      (MSG_INDEX_MAX_GAPM/PORT_MSG_TBL_ITEM_BIT_CNT+1)
#define PORT_MSG_GRP_TBL_ITEM_CNT_GAPC      (MSG_INDEX_MAX_GAPC/PORT_MSG_TBL_ITEM_BIT_CNT+1)
#define PORT_MSG_GRP_TBL_ITEM_CNT_APP       1
#define PORT_MSG_GRP_TBL_ITEM_CNT_MESH      1


/**
 * @brief 各消息组 (msg_grp) 在消息表 (msg_tbl) 中的 (起始) 索引值
 */
typedef enum _port_msg_grp_tbl_index_t{
    PORT_MSG_GRP_TBL_INDEX_LLC  = 0,
    PORT_MSG_GRP_TBL_INDEX_LLD  = 0, 
    PORT_MSG_GRP_TBL_INDEX_HCI  = 0, 
    PORT_MSG_GRP_TBL_INDEX_L2CC = 0,
    PORT_MSG_GRP_TBL_INDEX_GATT = 0,
    PORT_MSG_GRP_TBL_INDEX_GAPM = PORT_MSG_GRP_TBL_INDEX_GATT + PORT_MSG_GRP_TBL_ITEM_CNT_GATT,
    PORT_MSG_GRP_TBL_INDEX_GAPC = PORT_MSG_GRP_TBL_INDEX_GAPM + PORT_MSG_GRP_TBL_ITEM_CNT_GAPM,
    PORT_MSG_GRP_TBL_INDEX_APP  = PORT_MSG_GRP_TBL_INDEX_GAPC + PORT_MSG_GRP_TBL_ITEM_CNT_GAPC,
    PORT_MSG_GRP_TBL_INDEX_MESH = 0,
} port_msg_grp_tbl_index_t;


typedef struct _port_msg_tbl_t
{
    union
    {
        uint8_t array_u8[0];
        struct
        {
            uint8_t gatt[PORT_MSG_GRP_TBL_ITEM_CNT_GATT];
            uint8_t gapm[PORT_MSG_GRP_TBL_ITEM_CNT_GAPM];
            uint8_t gapc[PORT_MSG_GRP_TBL_ITEM_CNT_GAPC];
        };
    };
} port_msg_tbl_t;

/**
 * @brief 消息的索引
 * @attention SDK 侧直接引用的值
 */
typedef uint8_t msg_index_t;

typedef uint8_t msg_param_size_t;


#define MSG_INFO_LIST_INDEX_INVALID (UINT8_MAX)
typedef uint8_t msg_info_list_index_t;

typedef struct _port_msg_info_t
{
    port_msg_grp_type_t grp_type;
    msg_index_t msg_index;
    uint8_t param[0];
} port_msg_info_t;

#define MSG_INFO_LIST_MAX_CNT   (30)

#define GET_MSG_PARAM_TYPE_BY_NAME(param_name) struct param_name

#define DEFINE_PORT_MSG_PARAM_BY_NAME(param_name) GET_MSG_PARAM_TYPE_BY_NAME(param_name) param_name

typedef union _port_msg_param_var_t
{   
    /**
     * @brief GATT
     */
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_cmp_evt);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_client_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_exc_mtu_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_disc_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_read_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_write_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_execute_write_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_mtu_changed_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_disc_svc_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_disc_svc_incl_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_disc_char_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_disc_char_desc_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_read_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_event_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_event_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_event_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_reg_to_peer_evt_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_send_evt_cmd);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_server_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_read_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_write_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_att_info_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_read_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_write_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_att_info_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_sdp_svc_disc_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_sdp_svc_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_transaction_to_error_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_unknown_msg_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_read_db_hash_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_db_hash_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_robust_db_cache_en_cmd);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_db_cache_out_of_sync_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_svc_chg_req_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_svc_chg_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gatt_con_info_ind);


    /**
     * @brief GAPM
     */
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_cmp_evt);

    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_config_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_reset_cmd);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_set_dev_config_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_set_channel_map_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_get_dev_info_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_dev_version_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_dev_bdaddr_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_dev_adv_tx_power_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_peer_name_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_sec_enc_aes_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_resolv_addr_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_gen_rand_addr_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_use_enc_block_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_gen_rand_nb_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_addr_solved_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_use_enc_block_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_gen_rand_nb_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_profile_task_add_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_profile_added_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_unknown_task_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_sugg_dflt_data_len_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_max_data_len_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_ral_addr_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_set_irk_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_lepsm_register_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_lepsm_unregister_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_le_test_mode_ctrl_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_le_test_end_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_iso_stat_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_sec_enc_ecc_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_gen_dh_key_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_get_pub_key_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_gen_dh_key_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_pub_key_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_get_ral_addr_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_list_set_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_list_size_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_cmp_evt);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_create_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_start_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_stop_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_delete_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_created_ind);

    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_activity_stopped_ind);

    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_set_adv_data_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_ext_adv_report_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_scan_request_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_sync_established_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_max_adv_data_len_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_nb_adv_sets_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_dev_tx_pwr_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapm_dev_rf_path_comp_ind);

    /**
     * @brief GAPC
     */
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_cmp_evt);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_connection_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_connection_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_disconnect_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_disconnect_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_connection_cfg);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_get_info_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_peer_att_info_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_peer_version_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_peer_features_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_con_rssi_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_get_dev_info_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_get_dev_info_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_dev_info_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_dev_info_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_param_update_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_param_update_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_param_update_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_param_updated_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_smp_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_bond_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_encrypt_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_security_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_sign_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_bond_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_bond_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_bond_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_encrypt_req_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_encrypt_cfm);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_encrypt_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_security_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_sign_counter_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_con_channel_map_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_le_ping_to_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_le_ping_to_val_ind);
    // DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_le_ping_to_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_le_pkt_size_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_le_pkt_size_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_key_press_notif_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_key_press_notif_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_phy_cmd);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_le_phy_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_chan_sel_algo_ind);
    DEFINE_PORT_MSG_PARAM_BY_NAME(gapc_set_pref_slave_latency_cmd);

} port_msg_param_var_t;

typedef enum{
    PORT_MSG_EARLY_HANDLER_STATUS_NONE,     // 无对应的有效的预处理 handelr
    PORT_MSG_EARLY_HANDLER_STATUS_CMPLT,    // 预处理 handelr 处理完成，直接返回
    PORT_MSG_EARLY_HANDLER_STATUS_RECORD,   // 预处理 handelr 处理完成，需要记录事件信息
} port_msg_early_handler_status_t;

typedef port_msg_early_handler_status_t (*port_msg_early_handler_t)(uint8_t conn_id, const port_msg_param_var_t *param);

typedef struct _port_msg_early_handler_info_t
{
    msg_index_t msg_index;
    port_msg_early_handler_t handler;
} port_msg_early_handler_info_t;


#define PORT_MSG_EVT_SECTION_BIT_CNT_MATCH_BYTE     3
#define PORT_MSG_EVT_SECTION_BIT_CNT_MATCH_POS     (8 - PORT_MSG_EVT_SECTION_BIT_CNT_MATCH_BYTE)

typedef struct _port_msg_param_match_info_t
{
    uint8_t size_byte   :PORT_MSG_EVT_SECTION_BIT_CNT_MATCH_BYTE;    // 匹配时比较的大小 (单位:字节)
    uint8_t pos_index   :PORT_MSG_EVT_SECTION_BIT_CNT_MATCH_POS;    // 匹配时比较的位置 (参数 param 转换为 u8 数组，需要比较的是从第几个下标的位置开始)
    uint8_t val;            // 匹配的值
} port_msg_param_match_info_t;

typedef union __packed _port_msg_evt_info_t
{
    uint32_t _val_u32;
    struct
    {
        port_msg_grp_type_t grp_type;
        msg_index_t msg_index;
        port_msg_param_match_info_t param_match;
    };
    
} port_msg_evt_info_t;

/**
 * @brief  PORT 侧 消息事件值的分段信息
 */
#define PORT_MSG_EVT_SECTION_START_BIT_MSG_GRP_TYPE     0
#define PORT_MSG_EVT_SECTION_START_BIT_MSG_INDEX        (PORT_MSG_EVT_SECTION_START_BIT_MSG_GRP_TYPE + 8)
#define PORT_MSG_EVT_SECTION_START_BIT_MATCH_BYTE       (PORT_MSG_EVT_SECTION_START_BIT_MSG_INDEX + 8)
#define PORT_MSG_EVT_SECTION_START_BIT_MATCH_POS        (PORT_MSG_EVT_SECTION_START_BIT_MATCH_BYTE + 3)
#define PORT_MSG_EVT_SECTION_START_BIT_MATCH_VAL        (PORT_MSG_EVT_SECTION_START_BIT_MATCH_POS + 5)

/**
 * @brief  PORT 侧 消息事件值的构造方法 (根据分段信息)
 */
#define PORT_MSG_EVT_MAKE_UP(msg_grp_type, msg_index, match_byte, match_pos, param_match_val)   \
    (   ((param_match_val)  <<  PORT_MSG_EVT_SECTION_START_BIT_MATCH_VAL)           \
    |   ((match_pos)        <<  PORT_MSG_EVT_SECTION_START_BIT_MATCH_POS)           \
    |   ((match_byte)       <<  PORT_MSG_EVT_SECTION_START_BIT_MATCH_BYTE)          \
    |   ((msg_index)        <<  PORT_MSG_EVT_SECTION_START_BIT_MSG_INDEX)           \
    |   ((msg_grp_type)     <<  PORT_MSG_EVT_SECTION_START_BIT_MSG_GRP_TYPE)        \
    )

/**
 * @brief  PORT 侧 消息事件进行参数匹配时，匹配的位置 (参数结构体转换成 U8 的数组的下标)
 */
#define PORT_MSG_EVT_PARAM_MATCH_POS_NONE     0     // 不进行参数匹配
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_1     0
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_2     1
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_3     2
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_4     3
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_5     4
#define PORT_MSG_EVT_PARAM_MATCH_POS_U8_6     5

/**
 * @brief  PORT 侧 消息事件进行参数匹配时，默认的匹配长度
 */
#define PORT_MSG_EVT_PARAM_MATCH_SIZE_NONE      0   // 不进行参数匹配
#define PORT_MSG_EVT_PARAM_MATCH_SIZE_1         1
#define PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT   PORT_MSG_EVT_PARAM_MATCH_SIZE_1


/**
 * @brief PORT 侧 不对消息事件的参数进行匹配
 * 
 * @note 可以直接填至参数匹配的几个参数项中 (size、pos、val)
 */
#define _PORT_MSG_EVT_PARAM_MATCH_NONE           0    // 不进行参数匹配

/**
 * @brief  PORT 侧的消息事件: BLE 开启
 */
#define PORT_MSG_EVT_BLE_ENABLE \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_RESET )

/**
 * @brief  平台侧的消息事件: ble_app 触发的事件
 */
#define PORT_MSG_EVT_SRC_BLE_APP    PORT_MSG_EVT_BLE_ENABLE

/**
 * @brief  平台侧的消息事件: GAPM_SET_DEV_CONFIG 事件
 */
#define PORT_MSG_EVT_SRC_GAPM_SET_DEV_CONFIG \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_SET_DEV_CONFIG )

/**
 * @brief  PORT 侧的消息事件: BLE 设置本端地址
 */
#define PORT_MSG_EVT_BLE_SET_LOCAL_ADDR     PORT_MSG_EVT_SRC_GAPM_SET_DEV_CONFIG
/**
 * @brief  PORT 侧的消息事件: BLE 设置角色
 */
#define PORT_MSG_EVT_BLE_SET_ROLE           PORT_MSG_EVT_SRC_GAPM_SET_DEV_CONFIG
/**
 * @brief  PORT 侧的消息事件: BLE 设置 MTU
 */
#define PORT_MSG_EVT_BLE_SET_MTU            PORT_MSG_EVT_SRC_GAPM_SET_DEV_CONFIG
/**
 * @brief  PORT 侧的消息事件: BLE 设置配对模式
 */
#define PORT_MSG_EVT_BLE_SET_PAIR_MODE      PORT_MSG_EVT_SRC_GAPM_SET_DEV_CONFIG

#define PORT_MSG_EVT_SRC_GAPM_ACTIVITY_START \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_START_ACTIVITY )

#define PORT_MSG_EVT_SRC_GAPM_ACTV_TYPE_ADV \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_ACTIVITY_CREATED_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_2, GAPM_ACTV_TYPE_ADV )

#define PORT_MSG_EVT_BLE_GAP_ADV_CREATE         PORT_MSG_EVT_SRC_GAPM_ACTV_TYPE_ADV

#define PORT_MSG_EVT_BLE_GAP_ADV_DATA_SET \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_SET_ADV_DATA )

#define PORT_MSG_EVT_BLE_GAP_SCAN_RSP_DATA_SET \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_SET_SCAN_RSP_DATA )

#define PORT_MSG_EVT_BLE_GAP_ADV_START  PORT_MSG_EVT_SRC_GAPM_ACTIVITY_START

#define PORT_MSG_EVT_BLE_GAP_ADV_STOP \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_ACTIVITY_STOPPED_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_2, GAPM_ACTV_TYPE_ADV )

#define PORT_MSG_EVT_BLE_GAP_ADV_DEL \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_DELETE_ACTIVITY), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_ACTV_TYPE_ADV )

#define PORT_MSG_EVT_SRC_GAM_SCAN_CREATE \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_ACTIVITY_CREATED_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_2, GAPM_ACTV_TYPE_SCAN )

#define PORT_MSG_EVT_BLE_GAP_SCAN_START     PORT_MSG_EVT_SRC_GAPM_ACTIVITY_START

#define PORT_MSG_EVT_BLE_GAP_SCAN_STOP \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_ACTIVITY_STOPPED_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_2, GAPM_ACTV_TYPE_SCAN )

#define PORT_MSG_EVT_SRC_GAP_SCAN_DEL \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_CMP_EVT), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPM_DELETE_ACTIVITY )

#define PORT_MSG_EVT_SRC_GAM_INIT_CREATE \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPM, MSG_IDX(GAPM_ACTIVITY_CREATED_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_2, GAPM_ACTV_TYPE_INIT )

#define PORT_MSG_EVT_SRC_GAP_REQ_UPD_CONN_PARAM \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPC, MSG_IDX(GAPC_PARAM_UPDATED_IND), \
    _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE )

#define PORT_MSG_EVT_BLE_GAP_CONN_START     PORT_MSG_EVT_SRC_GAPM_ACTIVITY_START

#define PORT_MSG_EVT_BLE_GAP_DISCONNECT \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPC, MSG_IDX(GAPC_DISCONNECT_IND), \
    _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE )

// Message GAPM_CMP_EVT(operation GAPM_STOP_ACTIVITY) and GAPM_ACTIVITY_STOPPED_IND
// #define PORT_MSG_EVT_BLE_GAP_CONNECT_REQ \
//     PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPC, MSG_IDX(GAPC_CONNECTION_IND), \
//     _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE, _PORT_MSG_EVT_PARAM_MATCH_NONE )

#define PORT_MSG_EVT_BLE_GAP_PAIR_REQ \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GAPC, MSG_IDX(GAPC_BOND_REQ_IND), \
    PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GAPC_PAIRING_REQ )

/* GATT  */
// service
#define PORT_MSG_EVT_BLE_GATT_DISC_SVC_ALL_CMPLT \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_CMP_EVT), \
   PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GATT_DISC_ALL_SVC )

#define PORT_MSG_EVT_BLE_GATT_DISC_SVC(uuid_len, uuid) \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_DISC_SVC_IND), \
    (uuid_len), PORT_MSG_EVT_PARAM_MATCH_POS_U8_6, (uuid) )

#define PORT_MSG_EVT_BLE_GATT_DISC_SVC_BY_UUID_CMPLT \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_CMP_EVT), \
   PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GATT_DISC_BY_UUID_SVC )

// characteristic
#define PORT_MSG_EVT_BLE_GATT_DISC_CHARA_ALL_CMPLT \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_CMP_EVT), \
   PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GATT_DISC_ALL_CHAR )

#define PORT_MSG_EVT_BLE_GATT_DISC_CHARA(uuid_len, uuid) \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_DISC_CHAR_IND), \
    (uuid_len), PORT_MSG_EVT_PARAM_MATCH_POS_U8_6, (uuid) )

#define PORT_MSG_EVT_BLE_GATT_DISC_CHARA_BY_UUID_CMPLT \
    PORT_MSG_EVT_MAKE_UP(PORT_MSG_GRP_TYPE_GATT, MSG_IDX(GATT_CMP_EVT), \
   PORT_MSG_EVT_PARAM_MATCH_SIZE_DEFAULT, PORT_MSG_EVT_PARAM_MATCH_POS_U8_1, GATT_DISC_BY_UUID_CHAR )

/* ==================== [Global Variables] ================================== */

extern uint32_t port_sys_clk;

/* ==================== [Global Prototypes] ================================= */

port_msg_info_t **port_msg_info_list_get(void);

xf_err_t port_msg_tbl_set(
    port_msg_grp_type_t grp_type,
    msg_index_t msg_index,
    const void *param
);

msg_info_list_index_t port_msg_tbl_get(
    port_msg_grp_type_t grp_type,
    msg_index_t msg_index,
    port_msg_param_var_t **param_get,
    port_msg_param_match_info_t param_match,
    uint16_t timeout_ms
);

msg_info_list_index_t port_msg_evt_get(
    uint32_t msg_evt,
    port_msg_param_var_t **param_get,
    uint16_t timeout_ms
);

xf_err_t port_msg_tbl_clear_by_index(
    msg_info_list_index_t list_index
);

/* ==================== [Macros] ============================================ */

/**
 * @brief 查询消息事件，并检查结果
 * @param index_get 查询到的消息事件的索引，值为 MSG_INFO_LIST_INDEX_INVALID 为无效状态，即未查询到此事件
 * @param msg_evt 要查询的消息事件
 * @param param_get 获取到的要查询的消息事件的参数
 * @param timeout_ms 查询的超时时间
 * 
 * @note 在超时时间内,如果未查询到事件,则会直接 return；
 *  如果查询到事件，则会继续往下执行
 */
#define port_msg_evt_get_with_check(index_get, msg_evt, param_get, timeout_ms)  \
{                                                                               \
    index_get = port_msg_evt_get(                                               \
        (msg_evt), (param_get), (timeout_ms));                                  \
    XF_CHECK(index_get == MSG_INFO_LIST_INDEX_INVALID, XF_ERR_TIMEOUT, TAG, "msg_evt get timeout!");                                           \
}

/**
 * @brief 查询消息事件，并检查结果
 * @param index_get 查询到的消息事件的索引，值为 MSG_INFO_LIST_INDEX_INVALID 为无效状态，即未查询到此事件
 * @param msg_evt 要查询的消息事件
 * @param param_get 获取到的要查询的消息事件的参数
 * @param timeout_ms 查询的超时时间
 * @param err_tag 错误处理的标签（出错时将会 goto 至此）
 * 
 * @note 在超时时间内,如果未查询到事件,则会goto 至错误处理的标签；
 *  如果查询到事件，则会继续往下执行
 */
#define port_msg_evt_get_with_check_goto(index_get, msg_evt, param_get, timeout_ms, err_tag)  \
{                                                                               \
    index_get = port_msg_evt_get(                                               \
        (msg_evt), (param_get), (timeout_ms));                                  \
    XF_CHECK_GOTO(index_get == MSG_INFO_LIST_INDEX_INVALID, err_tag, TAG, "msg_evt get timeout!");                                           \
}

/**
 * @brief 清除指定索引的消息事件 （带有可优化的断言检查）
 * @param index_get 要清除的消息事件的索引
 */
#define port_msg_evt_clear_with_assert(index)                       \
{                                                                   \
    xf_err_t _ret = port_msg_tbl_clear_by_index(index);             \
    XF_ASSERT( _ret == XF_OK, _ret, TAG, "msg evt clear failed");   \
}

/**
 * @brief 清除指定索引的消息事件 （带有可优化的断言检查）
 * @param index_get 要清除的消息事件的索引
 * @param err_tag 错误处理的标签（出错时将会 goto 至此）
 */
#define port_msg_evt_clear_with_assert_goto(index, err_tag)         \
{                                                                   \
    xf_err_t _ret = port_msg_tbl_clear_by_index(index);             \
    XF_ASSERT_GOTO( _ret == XF_OK, err_tag, TAG, "msg evt clear failed");   \
}

/**
 * @brief 查询消息事件，并检查结果，以及其后需要时自动清除事件
 * @param msg_evt 要查询的消息事件
 * @param timeout_ms 查询的超时时间
 * 
 * @note 此函数一般用于只想知道事件触发与否，不关心参数内容的情况。
 *  如没触发则 直接 return；如果触发了，则立即调用清除事件函数。
 */
#define port_msg_evt_get_with_check_and_clear(msg_evt, timeout_ms)          \
{                                                                           \
    msg_info_list_index_t _index = MSG_INFO_LIST_INDEX_INVALID;             \
    port_msg_evt_get_with_check(_index, msg_evt, NULL, timeout_ms);         \
    port_msg_evt_clear_with_assert(_index);                                 \
}

/**
 * @brief 查询消息事件，并检查结果，以及其后需要时自动清除事件
 * @param msg_evt 要查询的消息事件
 * @param timeout_ms 查询的超时时间
 * @param err_tag_get 事件查询错误处理的标签（出错时将会 goto 至此）
 * @param err_tag_clear 事件清除错误处理的标签（出错时将会 goto 至此）
 * 
 * @note 此函数一般用于只想知道事件触发与否，不关心参数内容的情况。
 *  如没触发则 goto 至错误处理的标签；如果触发了，则立即调用清除事件函数。
 */
#define port_msg_evt_get_with_check_and_clear_goto(msg_evt, timeout_ms, err_tag_get, err_tag_clear)    \
{                                                                                       \
    msg_info_list_index_t _index = MSG_INFO_LIST_INDEX_INVALID;                         \
    port_msg_evt_get_with_check_goto(_index, msg_evt, NULL, timeout_ms, err_tag_get);   \
    port_msg_evt_clear_with_assert_goto(_index, err_tag_clear);                         \
}

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif

#endif // __PORT_BASE_H__
